﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.UI.EM.Views.Interfaces;
using Common.Model;
using System.Data.Objects.DataClasses;
using Common.Services;
using Microsoft.Practices.Composite.Presentation.Commands;
using System.ComponentModel;
using System.Windows;

namespace Common.UI.EM.Views
{
    public class DetailPresentationModel<S, E, C, EV> : IDetailPresentationModel<S, E, C, EV>, INotifyPropertyChanged
        where S : IGenericEntityManagerService<E, C, EV>, new()
        where E : EntityObject
        where C : CriteriaEntity
        where EV : ViewEntity
    {

        #region IDetailPresentationModel<S,E,C,EV> Members

        public event CancelCalledEventHandler CancelCalled;
        public event SaveCalledEventHandler SaveCalled;

        #endregion

        E _entityObject;
        public E EntityObject
        {
            get { return _entityObject; }
            set
            {
                _entityObject = value;
                this.OnPropertyChanged("EntityObject");
            }
        }

        public IDetailView View
        {
            get;
            set;
        }

        IGenericEntityManagerService<E, C, EV> _entityManager;
        public IGenericEntityManagerService<E, C, EV> EntityManager
        {
            get
            {
                if (_entityManager == null)
                {
                    _entityManager = new S();
                }
                return _entityManager;
            }
        }

        public DelegateCommand<Object> SaveCommand
        {
            get;
            set;
        }
        public DelegateCommand<Object> CancelCommand
        {
            get;
            set;
        }

        DetailMode _mode;
        public DetailMode Mode
        {
            get { return _mode; }
            set
            {
                _mode = value;
                OnPropertyChanged("Mode");
                this.RefreshMode();
            }
        }
        Boolean _isInAddMode;
        public Boolean IsInAddMode
        {
            get { return _isInAddMode; }
            set
            {
                _isInAddMode = value;
                OnPropertyChanged("IsInAddMode");
            }
        }
        Boolean _isInModifyMode;
        public Boolean IsInModifyMode
        {
            get { return _isInModifyMode; }
            set
            {
                _isInModifyMode = value;
                OnPropertyChanged("IsInModifyMode");
            }
        }
        Boolean _isInViewMode;
        public Boolean IsInViewMode
        {
            get { return _isInViewMode; }
            set
            {
                _isInViewMode = value;
                OnPropertyChanged("IsInViewMode");
            }
        }
        Boolean _isNotInViewMode;
        public Boolean IsNotInViewMode
        {
            get { return _isNotInViewMode; }
            set
            {
                _isNotInViewMode = value;
                OnPropertyChanged("IsNotInViewMode");
            }
        }

        private void RefreshMode()
        {
            this.IsInAddMode = Mode == DetailMode.Add;
            this.IsInModifyMode = Mode == DetailMode.Modify;
            this.IsInViewMode = Mode == DetailMode.View;
            IsNotInViewMode = Mode != DetailMode.View;
        }


        public DetailPresentationModel(IDetailView view)
        {
            this.View = view;
            this.View.Model = this;
            this.AddCommands();
        }

        private void AddCommands()
        {
            this.SaveCommand = new DelegateCommand<object>(ExecuteSaveCommand, CanExecuteSaveCommand);
            this.CancelCommand = new DelegateCommand<object>(ExecuteCancelCommand, CanExecuteCancelCommand);

            this.AddCustomCommands();
        }

        protected virtual void AddCustomCommands()
        {
        }


        private void ExecuteSaveCommand(Object arg)
        {
            if (this.Validate())
            {
                this.Save();

                this.AfterSave();

                if (SaveCalled != null)
                {
                    SaveCalled(this, new EventArgs());
                }
            }
        }

        protected virtual void AfterSave()
        {
        }

        private void Save()
        {
            EntityManager.Save(this.EntityObject);
        }

        protected virtual Boolean Validate()
        {
            var rta = this.View.Validate();
            if (!rta)
            {
                var str = new StringBuilder();
                foreach (var item in this.View.ErrorMessages)
                {
                    str.AppendLine(item);
                }
                MessageBox.Show(str.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }

            return rta;
        }

        private Boolean CanExecuteSaveCommand(Object arg)
        {
            return true;
        }


        private void ExecuteCancelCommand(Object arg)
        {
            EntityManager.RejectChanges();

            if (CancelCalled != null)
            {
                this.CancelCalled(this, new EventArgs());
            }
        }

        private Boolean CanExecuteCancelCommand(Object arg)
        {
            return true;
        }


        public virtual void LoadEntity(Guid id)
        {
            LoadEntity(EntityManager.Read(id));
        }

        public void LoadEntity(E entityObject)
        {
            this.EntityObject = entityObject;
        }

        public void LoadEntity(EV ev)
        {
            this.EntityObject = EntityManager.Read(ev.ID);
        }


        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}